import os
import re
import time
import packaging
from adbutils import adb
import uiautomator2 as u2
from uiautomator2 import UiObject

from TODO.wechat_uielements import Wchat_uielements, Wechat_Uielements2
from weixin_modules.oper_database import OperDatabase
from weixin_modules.other_fun import get_puyang_keys
from weixin_modules.retry import retries
from weixin_modules.inner_settings import file_log
import logging

from weixin_modules.wechat import wechat_timeout, sleep_for_polling_interval

# serialno, device_name = select_phone()
# logger = init_logger(serialno, device_name)
logger = logging.getLogger("uiauto_weixin.te_3")
print("weixin_actions.py", __name__)


def click_wait_for_appearance(ui: UiObject, apper_ui: UiObject):
    """
    点击 ui 元素，
    并等待新的元素出现，
    :return:
    """
    logger.debug("click_wait_for_appearance,进入")
    start = time.time()
    while True:
        if ui.wait(timeout=5):
            ui.click()
        if time.time() - start > wechat_timeout:
            raise Exception('点击后，UI元素没有出现，超时了，请检查')
        if apper_ui.wait(timeout=sleep_for_polling_interval):
            break
        logger.debug("click_wait_for_appearance,进入循环判断")


def click_wait_for_appearance2(ui: UiObject, *args):
    """
    点击 ui 元素，
    并等待新的元素出现，
    :return:
    """
    logger.debug("click_wait_for_appearance2,进入")
    start = time.time()
    while True:
        if ui.wait(timeout=5):
            ui.click()
        if time.time() - start > wechat_timeout:
            break
            # raise Exception('点击后，UI元素没有出现，超时了，请检查')
        flag = False
        for arg in args:
            if arg.wait(timeout=sleep_for_polling_interval):
                flag = True
                break
        if flag:
            break
        logger.debug("click_wait_for_appearance,进入循环判断")





def get_text(uis):
    """
    同一个目标,多次尝试点击不同的元素,
    :param uis:
    :return:
    """
    for ui in uis:
        try:
            data = ui.get_text()
            return data
        except Exception as e:
            print("Caught an exception:", e)
            uis.client.debug_save()
    # TODO:下载当前xml文件,截图保存,
    # 抛出异常并附加额外信息
    raise Exception("发生错误")


def click(uis):
    """
    同一个目标,多次尝试点击不同的元素,
    :param uis:
    :return:
    """
    for ui in uis:
        try:
            ui.click()
            return True
        except Exception as e:
            print("Caught an exception:", e)
            uis.client.debug_save()
    # TODO:下载当前xml文件,截图保存,
    # 抛出异常并附加额外信息
    raise Exception("发生错误")


class WeixinAction:

    def __init__(self, serialno):
        # 判断 微信的版本号，8.0.40以后，app的层发生了变化 ，
        self.serialno = serialno
        ver = packaging.version.parse("8.0.41")
        d = adb.device(serialno)
        info = d.app_info("com.tencent.mm")
        logger.info(f"微信版本号：{info.version_name}, version_code:{info.version_code}")
        self.d = u2.connect(serialno)
        info_dict = self.d.device_info
        self.prop = "brand:{brand}, model:{model}, serial:{serial}".format(**info_dict)
        self.adb = self.d._adb_device
        if packaging.version.parse(info.version_name) < ver:
            self.wechat = Wchat_uielements(self)
        else:
            print("选择版本2")
            self.wechat = Wechat_Uielements2(self)

        self.other_list = ["微信运动", "文件传输助手", "微信支付", "折叠的群聊", "订阅号消息", "服务通知",
                           "微信支付商家助手", "腾讯新闻", "已注销的微信用户", "微信团队"]

        # # 品牌
        # self.device_manufacturer = self.wechat.device_manufacturer
        # # 型号,
        # self.device_model = self.wechat.device_model
        # 点击返回后的等待时间,
        self.back_wait_time = 0.5
        # # 唤醒手机,
        self.wake()
        # 进入微信,
        self.enter_wx()
        self.nick_name = None
        self.wxid = None
        self.tag_id = None
        self.get_current_wxinfo()
        # 初始化数据库，
        # 初始化数据库，
        self.database = OperDatabase(self.wxid)
        self.tag_id = self.database.select_user(self.nick_name, self.wxid)
        # self.wechat.info_area = self.get_info_area()
        # 濮阳关键字，
        self.puyang_keys = get_puyang_keys()
        # 1FABA 🪺 NEST WITH EGGS 蛋窝 标志，用于标识微信群，
        # self.flag_rooms = chr(0x1FABA)
        # self.flag_rooms2 = chr(0x1FAB9)
        # 1FAAA 🪪 IDENTIFICATION CARD
        # 用于识别好友，
        # self.flag_friend = chr(0x1FAAA)
        self.room_serialno = None
        # 群发任务
        self.task_id = None
        self.task_message = None
        self.task_rooms = None
        #
        self.friend_serialno = None

        self.internal_flag_auto_accept_friend_invitations = 1
        # 临时用法，设置默认等待时间，
        self.weinxinTest_default_waiting_time = 2
        if serialno == "721QADRP232N4":
            self.weinxinTest_default_waiting_time = 6

    def key_back(self):
        """
        点击 返回键
        :return:
        """
        # keyevent 方法 直接调用 shell，更直接
        # 比 press方法更直接，
        self.d.keyevent("BACK")

    def keyback_wait_for_disappearance(self, ui: UiObject):
        """
        点击 返回，并等待当前元素消失，
        keyback ，原操作是没有加等待的，
        所以这里先等待，再判断
        :return:
        """
        self.key_back()
        start = time.time()
        time.sleep(sleep_for_polling_interval)
        while ui.exists():
            self.key_back()
            time.sleep(sleep_for_polling_interval)
            if time.time() - start > wechat_timeout:
                raise Exception('返回后，UI元素没有消失，超时了，请检查')


    def keyback_wait_for_appearance(self, ui: UiObject, timeout=2):
        """
        点击 返回，并等待新的元素出现，
        :param ui:
        :return:
        """
        logger.debug("keyback_wait_for_appearance")
        self.key_back()
        # self.debug_save("721QADRP232N4")
        dealline = time.time() + wechat_timeout
        while not ui.wait(timeout=timeout):
            logger.debug("进入循环 key_back")
            self.key_back()
            # self.debug_save("721QADRP232N4")
            if time.time() > dealline:
                raise Exception('返回后，UI元素没有出现，超时了，请检查')
            if not self.is_in_weixinapp():
                logger.debug("keyback_wait_for_appearance,已经跳出微信了")
                raise Exception("已经跳出微信了")

    def keyback_wait_for_appearance2(self, *args):
        """
        点击 返回，并等待新的元素出现，
        :param ui:
        :return:
        """
        logger.debug("keyback_wait_for_appearance")
        self.key_back()
        # self.debug_save("721QADRP232N4")
        dealline = time.time() + wechat_timeout
        while True:
            n = 0
            flag = False
            for arg in args:
                n += 1
                if arg.wait(timeout=2):
                    logger.debug(f"判断次数：{n}")
                    flag = True
                    break
            if flag:
                break
            logger.debug("进入循环 key_back")
            self.key_back()
            # self.debug_save("721QADRP232N4")

            if time.time() > dealline:
                raise Exception('返回后，UI元素没有出现，超时了，请检查')
            if not self.is_in_weixinapp():
                logger.debug("keyback_wait_for_appearance,已经跳出微信了")
                raise Exception("已经跳出微信了")


    def keyback_homepage(self, timeout=2):
        """
        判断是否在首页，
        从其它页面，返回首页
        :return:
        """
        logger.debug("keyback_homepage")
        # self.key_back()
        # self.debug_save("721QADRP232N4")
        dealline = time.time() + wechat_timeout
        while not self.navbar.wait(timeout=timeout):
            self.key_back()
            logger.debug("进入循环 key_back")
            # self.debug_save("721QADRP232N4")
            if time.time() > dealline:
                raise Exception('返回后，UI元素没有出现，超时了，请检查')
            # {'package': 'com.meizu.flyme.launcher', 'activity': 'com.meizu.flyme.launcher.Launcher'}
            # {'package': 'com.tencent.mm', 'activity': 'com.tencent.mm.ui.LauncherUI'}
            if not self.is_in_weixinapp():
                logger.debug("keyback_homepage,已经跳出微信了")
                raise Exception("已经跳出微信了")

    def is_in_weixinapp(self):
        """
        判断当前界面是否在微信界面，
        :return:
        """
        current_appinfo = self.d.app_current()
        current_package = current_appinfo["package"]
        if current_package == 'com.tencent.mm':
            return True
        return False

    def double_click(self, ui_object):
        """
        TODO: 需要调整
        poco 没有实现，双击，
        只能自己实现，
        把相对坐标，转换为绝对坐标，
        然后调用airtest.Android.double_click
        :return:
        """
        point = ui_object.center()
        self.d.double_click(*point)


    def to_top(self):
        """
        微信 让信息流回到顶部
        :return:
        """
        point = self.d(resourceId="android:id/text1").center()
        self.d.double_click(*point)

    def swipe_up(self, start, time=1.0):
        """
        向上划，
        swipe_ext,中的scale是屏幕中间的部分，
        :param start:起始的 相对坐标 y
        :param time: 划动的时间，
        :return:
        """
        self.d.swipe(0.5, start, 0.5, 0.1, duration=time)

    def swipe_to_top(self, rows):
        """
        信息行 row,从 第-2个，上划到第0个
        代替drag_to
        :return:
        """
        start = rows[-2].center()
        end = rows[0].center()
        # start end 都是元组，用*解包
        self.d.swipe(*start, *end, steps=50)

    def debug_save(self):
        """
        调试某个手机是 保存截图和xml文件
        :param phone_serial:
        :return:
        """
        time.sleep(2)
        logger.debug("保存截图和xml文件")
        # 主要是m6 经常出现问题，所以，m6需要返回第2次时，
        # 截图，保存xml,
        current_datetime = time.strftime("%Y-%m-%d %H-%M-%S", time.localtime())
        folder_path = os.path.join(file_log, self.serialno, "debug")
        # print(folder_path)
        if not os.path.exists(folder_path):
            os.makedirs(folder_path)
        screenshot_name = os.path.join(folder_path, current_datetime + ".jpg")
        # print(screenshot_name)
        logger.debug(f"截图：{screenshot_name}")
        self.d.screenshot(screenshot_name)
        xml_name = os.path.join(folder_path, current_datetime + ".xml")
        logger.debug(f"xml文件：{xml_name}")
        xml = self.d.dump_hierarchy()
        with open(xml_name, "w") as f:
            f.write(xml)

    def screen_off(self):
        self.d.screen_off()

    @retries(max_tries=3)
    def is_locked(self):
        """
        Perform `adb shell dumpsys window policy` command and search for information if screen is locked or not

        Raises:
            AirtestError: if lock screen can't be detected

        Returns:
            True or False whether the screen is locked or not

        """
        lockScreenRE = re.compile('(?:mShowingLockscreen|isStatusBarKeyguard|showing)=(true|false)')
        m = lockScreenRE.search(self.adb.shell('dumpsys window policy'))
        if not m:
            raise Exception("Couldn't determine screen lock state")
        return (m.group(1) == 'true')

    def wake(self):
        """
        唤醒手机，解锁屏幕，
        https://blog.csdn.net/weixin_44867493/article/details/105811826
        学习案例

        :return:
        """
        # 唤醒手机,
        # self.dev.wake()
        # self.d.screen_on()
        # self.d.keyevent()
        # self.d.press()
        # 先尝试连续发送224和82解锁屏幕，如果解锁失败，再试用yosemite解锁
        self.adb.keyevent("KEYCODE_WAKEUP")
        if self.is_locked():
            print("1次是锁屏状态")
            self.adb.keyevent("KEYCODE_MENU")
            time.sleep(0.5)
        if self.is_locked():
            print("2次是锁屏状态")
            self.adb.keyevent("HOME")
            self.d.swipe(0.1, 0.9, 0.9, 0.1)

    def screen_turn_off(self):
        self.d.screen_off()
    def enter_wx(self):
        """
        进入微信
        :return:
        """
        self.switch_to_wechat()
        # TODO: 这里还需要加其它判断，
        # if not self.wechat.navbar.wait(timeout=5):
        #     logger.debug("微信导航栏不存在")
        #     self.wechat.keyback_homepage()
        logger.info(f'进入微信：{self.prop}')

    def switch_to_wechat(self):
        """
        切换到微信界面
        :return:
        """
        # 微信包名：com.tencent.mm
        app_info_dict = self.d.app_current()
        app_name = app_info_dict["package"]
        logger.info(f"当前运行的app是：{app_name}")
        logger.debug("启动微信")
        # self.d.app_start('com.tencent.mm')
        self.d.app_start(package_name='com.tencent.mm', activity='com.tencent.mm.ui.LauncherUI', wait=True, stop=True,
                         use_monkey=True)

    def get_current_wxinfo(self):
        """
        获取连接的手机上的微信 信息，
        :return:
        """
        # :进入 我，识别名字和wxid,
        # 解决 IQOO z7i 手机，点击 <我>， 失败的问题，
        # uiautomator2.exceptions.UiObjectNotFoundError: -32002 Client error: <> data:
        # Selector [resourceId='com.tencent.mm:id/h7q', text='我'], method: None

        self.click(self.wechat.navbar_me)
        nick_name = get_text(self.wechat.me_nick_name)
        # 总结 应该是两个限制 ，UTF-8最长为36，字符对象最多为23，
        self.nick_name = nick_name.strip()
        if self.nick_name.endswith("…"):
            self.nick_name = self.nick_name[:-1]
        # 微信号：wxid_6n4jvt7px62p22
        wxid = get_text(self.wechat.me_wxid)
        wxid = wxid[4:]
        self.wxid = wxid.strip()
        logger.info(f"当前微信名：{self.nick_name}")
        logger.info(f"当前微信号：{wxid}")

    def is_clickable(self, ui: UiObject):
        """
        判断当前相对位置 是否可以点击,
        是否被标题栏和导航栏 遮挡,
        :param pos:
        :return:
        """
        pos = ui.center()
        if self.info_area[0] < pos[1] < self.info_area[1]:
            # 在区域内,可点击,
            return True
        else:
            return False

    def get_info_area(self):
        """
        找到信息流，可点击区域的上下边界，
        :return:
        """
        # 点击 底部导航栏的 >微信<
        click(self.wechat.navbar_weixin)

        top_line = self.weixin_title_bar.bounds()[3]
        bottom_line = self.weixin_bottom_navigation_bar.bounds()[1]
        return [top_line, bottom_line]

    def is_closed(self, ui: UiObject):
        """
        判断 群聊信息 界面 的开关按钮的状态，
        :param ui:
        :return:
        """
        # self.debug_save("721QADRP232N4")
        pos = ui.center()
        # logger.debug(f"当前元素的中心点是：{pos}")
        rgb = self.d.image.getpixel(*pos)
        # logger.debug(f"当前元素的中心点的颜色是：{rgb}")
        return all(i == rgb[0] for i in rgb)


if __name__ == '__main__':
    WeixinAction()
